---
title: 'Custom Variables'
description: 'Pass dynamic data to your Droidrun agents using the `variables` parameter. Variables enable parameterized workflows and reusable automation.'
---

Custom variables are accessible in:
- **Agent prompts** via custom Jinja2 templates
- **Custom tools** via `shared_state.custom_variables`

---

## Quick Start

```python
from droidrun import DroidAgent, DroidrunConfig

# Define custom prompts that render variables
custom_prompts = {
    "manager_system": """
{{ instruction }}

{% if variables %}
Available variables:
{% for key, value in variables.items() %}
- {{ key }}: {{ value }}
{% endfor %}
{% endif %}
    """
}

# Create agent with variables
config = DroidrunConfig()

agent = DroidAgent(
    goal="Send email to recipient with subject",
    config=config,
    variables={"recipient": "john@example.com", "subject": "Update"},
    prompts=custom_prompts  # Required to see variables
)

result = await agent.run()
```

**Important:** Default prompts don't render variables. You must provide custom prompts via the `prompts` parameter.

---

## How Variables Work

When you pass `variables` to `DroidAgent`:

1. **Stored** in `DroidAgentState.custom_variables`
2. **Passed** to prompt templates as `variables` dict
3. **Rendered** in Jinja2 templates via `{% if variables %}` blocks
4. **Available** to all child agents throughout the workflow

**Access Summary:**
- ✅ Agent prompts (via custom Jinja2 templates)
- ✅ Agents can read and pass to tools as arguments
- ✅ Custom tools (via `shared_state.custom_variables`)

---

## Basic Usage

```python
from droidrun import DroidAgent, DroidrunConfig

# Define variables
variables = {
    "recipient": "alice@example.com",
    "message": "Hello from Droidrun!"
}

# Custom prompt to render variables
custom_prompts = {
    "codeact_system": """
You are an agent that controls Android devices.

{% if variables %}
Available variables:
{% for key, value in variables.items() %}
- {{ key }}: {{ value }}
{% endfor %}
{% endif %}

Use these variables when executing tasks.
    """
}

# Create agent
config = DroidrunConfig()

agent = DroidAgent(
    goal="Send message to recipient",
    config=config,
    variables=variables,
    prompts=custom_prompts
)

result = await agent.run()
```

### Available Prompt Keys

Customize these prompts to render variables:

- `manager_system` - Manager agent system prompt
- `executor_system` - Executor agent system prompt
- `codeact_system` - CodeAct agent system prompt
- `codeact_user` - CodeAct agent user prompt
- `scripter_system` - Scripter agent system prompt

---

## Accessing Variables in Custom Tools

Custom tools can directly access variables via the `shared_state` keyword argument:

```python
from droidrun import DroidAgent, DroidrunConfig

def send_notification(title: str, *, tools=None, shared_state=None, **kwargs):
    """Send a notification using channel from custom variables.

    Args:
        title: Notification title
        tools: Tools instance (optional, injected automatically)
        shared_state: DroidAgentState (optional, injected automatically)
    """
    if not shared_state:
        return "Error: shared_state required"

    # Access custom variables
    channel = shared_state.custom_variables.get("notification_channel", "default")
    return f"Sent '{title}' to {channel}"

custom_tools = {
    "send_notification": {
        "arguments": ["title"],
        "description": "Send a notification with title. Usage: {\"action\": \"send_notification\", \"title\": \"Alert\"}",
        "function": send_notification
    }
}

config = DroidrunConfig()

agent = DroidAgent(
    goal="Send notification with title 'Alert'",
    config=config,
    custom_tools=custom_tools,
    variables={"notification_channel": "alerts"}
)
```

---

## Use Cases

### Parameterized Workflows

```python
# Define reusable workflow with different variables
for user in ["alice@example.com", "bob@example.com"]:
    agent = DroidAgent(
        goal="Send welcome email",
        config=config,
        variables={"recipient": user},
        prompts=custom_prompts
    )
    await agent.run()
```

### Configuration Data

```python
variables = {
    "api_endpoint": "https://api.example.com/v2",
    "timeout": 30
}

agent = DroidAgent(
    goal="Call API endpoint",
    config=config,
    variables=variables,
    prompts=custom_prompts
)
```

---

## Key Points

1. **Custom prompts required** - Default prompts don't render variables in agent context
2. **Direct access in tools** - Custom tools access `shared_state.custom_variables` via keyword argument
3. **Available to all agents** - Manager, Executor, CodeAct, Scripter all receive variables
4. **Jinja2 templates** - Use `{% if variables %}` blocks in custom prompts
5. **Auto-injection** - `tools` and `shared_state` are injected automatically by Droidrun

## Related Documentation

- [Custom Prompts](/concepts/prompts) - How to customize agent prompts
- [Custom Tools](/features/custom-tools) - Creating custom tool functions
- [DroidAgent SDK](/sdk/droid-agent) - Complete API reference
